package com.xxl.job.core.context;

import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.util.DateUtil;
import com.xxl.job.core.util.ThrowableUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;

import java.util.Date;

/**
 * helper for xxl-job
 *
 * @author xuxueli
 * @since 2020-11-05
 */
public class XxlJobHelper {

	// ---------------------- base info ----------------------

	/**
	 * current JobId
	 * @return
	 */
	public static long getJobId() {
		XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
		if (xxlJobContext == null) {
			return -1;
		}

		return xxlJobContext.getJobId();
	}

	/**
	 * current JobParam
	 * @return
	 */
	public static String getJobParam() {
		XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
		if (xxlJobContext == null) {
			return null;
		}

		return xxlJobContext.getJobParam();
	}

	// ---------------------- for log ----------------------

	/**
	 * current JobLogFileName
	 * @return
	 */
	public static String getJobLogFileName() {
		XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
		if (xxlJobContext == null) {
			return null;
		}

		return xxlJobContext.getJobLogFileName();
	}

	// ---------------------- for shard ----------------------

	/**
	 * current ShardIndex
	 * @return
	 */
	public static int getShardIndex() {
		XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
		if (xxlJobContext == null) {
			return -1;
		}

		return xxlJobContext.getShardIndex();
	}

	/**
	 * current ShardTotal
	 * @return
	 */
	public static int getShardTotal() {
		XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
		if (xxlJobContext == null) {
			return -1;
		}

		return xxlJobContext.getShardTotal();
	}

	// ---------------------- tool for log ----------------------

	private static final Logger logger = LoggerFactory.getLogger("xxl-job logger");

	/**
	 * append log with pattern
	 * @param appendLogPattern like "aaa {} bbb {} ccc"
	 * @param appendLogArguments like "111, true"
	 */
	public static boolean log(String appendLogPattern, Object... appendLogArguments) {

		FormattingTuple ft = MessageFormatter.arrayFormat(appendLogPattern, appendLogArguments);
		String appendLog = ft.getMessage();

		/*
		 * appendLog = appendLogPattern; if (appendLogArguments!=null &&
		 * appendLogArguments.length>0) { appendLog =
		 * MessageFormat.format(appendLogPattern, appendLogArguments); }
		 */

		StackTraceElement callInfo = new Throwable().getStackTrace()[1];
		return logDetail(callInfo, appendLog);
	}

	/**
	 * append exception stack
	 * @param e
	 */
	public static boolean log(Throwable e) {

		String appendLog = ThrowableUtil.toString(e);

		StackTraceElement callInfo = new Throwable().getStackTrace()[1];
		return logDetail(callInfo, appendLog);
	}

	/**
	 * append log
	 * @param callInfo
	 * @param appendLog
	 */
	private static boolean logDetail(StackTraceElement callInfo, String appendLog) {
		XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
		if (xxlJobContext == null) {
			return false;
		}

		/*
		 * //
		 * "yyyy-MM-dd HH:mm:ss [ClassName]-[MethodName]-[LineNumber]-[ThreadName] log";
		 * StackTraceElement[] stackTraceElements = new Throwable().getStackTrace();
		 * StackTraceElement callInfo = stackTraceElements[1];
		 */

		String formatAppendLog = DateUtil.formatDateTime(new Date()) + " " + "[" + callInfo.getClassName() + "#"
				+ callInfo.getMethodName() + "]" + "-" + "[" + callInfo.getLineNumber() + "]" + "-" + "["
				+ Thread.currentThread().getName() + "]" + " " + (appendLog != null ? appendLog : "");

		// appendlog
		String logFileName = xxlJobContext.getJobLogFileName();

		if (logFileName != null && !logFileName.trim().isEmpty()) {
			XxlJobFileAppender.appendLog(logFileName, formatAppendLog);
			return true;
		}
		else {
			logger.info(">>>>>>>>>>> {}", formatAppendLog);
			return false;
		}
	}

	// ---------------------- tool for handleResult ----------------------

	/**
	 * handle success
	 * @return
	 */
	public static boolean handleSuccess() {
		return handleResult(XxlJobContext.HANDLE_CODE_SUCCESS, null);
	}

	/**
	 * handle success with log msg
	 * @param handleMsg
	 * @return
	 */
	public static boolean handleSuccess(String handleMsg) {
		return handleResult(XxlJobContext.HANDLE_CODE_SUCCESS, handleMsg);
	}

	/**
	 * handle fail
	 * @return
	 */
	public static boolean handleFail() {
		return handleResult(XxlJobContext.HANDLE_CODE_FAIL, null);
	}

	/**
	 * handle fail with log msg
	 * @param handleMsg
	 * @return
	 */
	public static boolean handleFail(String handleMsg) {
		return handleResult(XxlJobContext.HANDLE_CODE_FAIL, handleMsg);
	}

	/**
	 * handle timeout
	 * @return
	 */
	public static boolean handleTimeout() {
		return handleResult(XxlJobContext.HANDLE_CODE_TIMEOUT, null);
	}

	/**
	 * handle timeout with log msg
	 * @param handleMsg
	 * @return
	 */
	public static boolean handleTimeout(String handleMsg) {
		return handleResult(XxlJobContext.HANDLE_CODE_TIMEOUT, handleMsg);
	}

	/**
	 * @param handleCode
	 *
	 * 200 : success 500 : fail 502 : timeout
	 * @param handleMsg
	 * @return
	 */
	public static boolean handleResult(int handleCode, String handleMsg) {
		XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
		if (xxlJobContext == null) {
			return false;
		}

		xxlJobContext.setHandleCode(handleCode);
		if (handleMsg != null) {
			xxlJobContext.setHandleMsg(handleMsg);
		}
		return true;
	}

}
